package com.javandad.app.client;

import java.util.Date;
import java.util.LinkedList;
import java.util.List;

import com.google.gwt.cell.client.DateCell;
import com.google.gwt.core.client.EntryPoint;
import com.google.gwt.core.client.GWT;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.event.logical.shared.SelectionEvent;
import com.google.gwt.event.logical.shared.SelectionHandler;
import com.google.gwt.user.cellview.client.CellTable;
import com.google.gwt.user.cellview.client.Column;
import com.google.gwt.user.cellview.client.SimplePager;
import com.google.gwt.user.cellview.client.TextColumn;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.AbsolutePanel;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.DecoratedTabPanel;
import com.google.gwt.user.client.ui.HorizontalPanel;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.RichTextArea;
import com.google.gwt.user.client.ui.RootPanel;
import com.google.gwt.user.client.ui.ScrollPanel;
import com.google.gwt.user.client.ui.TextArea;
import com.google.gwt.user.client.ui.TextBox;
import com.google.gwt.user.client.ui.VerticalPanel;
import com.google.gwt.view.client.AsyncDataProvider;
import com.google.gwt.view.client.HasData;
import com.google.gwt.view.client.SelectionChangeEvent;
import com.google.gwt.view.client.SelectionModel;
import com.google.gwt.view.client.SingleSelectionModel;
import com.javandad.app.shared.entity.Friendship;
import com.javandad.app.shared.entity.Message;
import com.javandad.app.shared.entity.Notification;
import com.javandad.app.shared.entity.project.ProjectAssoc;

public class MessageBoxMainFrame implements EntryPoint {

	public final static int NUMBER_OF_TABS = 4;

	private final MessageBoxServiceAsync messageBoxService = GWT.create(MessageBoxService.class);

	protected String username = "nouser";

	private void initGUI() {

		tabPanel.setAnimationEnabled(true);

		tabPanel.setWidth("100%");
		tabPanel.setHeight("600px");

		tabs = new AbsolutePanel[NUMBER_OF_TABS];

		inbox = new CellTable<Message>();
		sentbox = new CellTable<Message>();

		inbox.setPageSize(10);
		inbox.setWidth("100%");
		sentbox.setPageSize(10);
		sentbox.setWidth("100%");

		TextColumn<Message> receiver = new TextColumn<Message>() {
			@Override
			public String getValue(Message message) {
				return message.getReceiver();
			}
		};
		sentbox.addColumn(receiver, "Receiver");

		TextColumn<Message> sender = new TextColumn<Message>() {
			@Override
			public String getValue(Message message) {
				return message.getSender();
			}
		};
		inbox.addColumn(sender, "Sender");

		TextColumn<Message> title = new TextColumn<Message>() {
			@Override
			public String getValue(Message message) {
				return message.getTitle();
			}
		};
		inbox.addColumn(title, "Title");
		sentbox.addColumn(title, "Title");

		DateCell dateCell = new DateCell();
		Column<Message, Date> date = new Column<Message, Date>(dateCell) {
			@Override
			public Date getValue(Message message) {
				return new Date(message.getDateOfDelivery().getTime());
			}
		};
		inbox.addColumn(date, "Date");
		sentbox.addColumn(date, "Date");

		final SimplePager pager1 = new SimplePager();
		pager1.setDisplay(inbox);

		final SelectionModel<Message> model = new SingleSelectionModel<Message>();
		inbox.setSelectionModel(model);
		model.addSelectionChangeHandler(new SelectionChangeEvent.Handler() {
			public void onSelectionChange(SelectionChangeEvent e) {

				for (Message message : inboxMessages) {
					if (model.isSelected(message)) {
						messageContent.setText(message.getContent());
						break;
					}
				}
			}

		});

		final SimplePager pager2 = new SimplePager();
		pager2.setDisplay(sentbox);

		final SelectionModel<Message> model2 = new SingleSelectionModel<Message>();
		sentbox.setSelectionModel(model2);
		model2.addSelectionChangeHandler(new SelectionChangeEvent.Handler() {
			public void onSelectionChange(SelectionChangeEvent e) {
				for (Message message : sentboxMessages) {
					if (model2.isSelected(message)) {
						messageContent2.setText(message.getContent());
						break;
					}
				}
			}

		});

		tabs[0] = new AbsolutePanel();
		tabs[0].add(inbox);
		tabs[0].add(pager1);

		messageContent = new TextArea();
		messageContent.setWidth("100%");
		messageContent.setHeight("400px");
		messageContent.setReadOnly(true);
		tabs[0].add(messageContent);

		tabs[1] = new AbsolutePanel();
		tabs[1].add(sentbox);
		tabs[1].add(pager2);

		messageContent2 = new TextArea();
		messageContent2.setWidth("100%");
		messageContent2.setHeight("400px");
		messageContent2.setReadOnly(true);

		tabs[1].add(messageContent2);

		tabs[2] = new AbsolutePanel();

		to.setWidth("100%");

		subject.setWidth("100%");

		content.setWidth("100%");
		content.setHeight("350px");

		send.setText("Send");
		send.addClickHandler(new ClickHandler() {

			@Override
			public void onClick(ClickEvent event) {
				sendMessage(new Message(session.get(1), to.getText(), content.getText(), subject.getText(), null));

			}
		});

		tabs[2].add(tol);
		tabs[2].add(to);

		tabs[2].add(subjectl);
		tabs[2].add(subject);

		tabs[2].add(contentl);
		tabs[2].add(content);
		tabs[2].add(send);

		tabs[3] = new AbsolutePanel();

		tabPanel.add(tabs[0], "inbox");
		tabPanel.add(tabs[1], "sentbox");
		tabPanel.add(tabs[2], "compose");
		tabPanel.add(tabs[3], "notibox");

		tabPanel.selectTab(0);

		tabPanel.addSelectionHandler(new SelectionHandler<Integer>() {

			@Override
			public void onSelection(SelectionEvent<Integer> event) {
				int tab = event.getSelectedItem();
				switch (tab) {
				case 0:
					if (session != null && session.get(1) != null) {
						getInboxMessages(session.get(1));
					}
					break;
				case 1:
					if (session != null && session.get(1) != null) {
						getSentboxMessages(session.get(1));
					}
					break;

				case 3:
					if (session != null && session.get(1) != null) {
						getNotiboxNotifications(session.get(1));
					}
					break;
				}
			}

		});

		RootPanel.get("messageBoxMainFrameContainer").add(tabPanel);

	}

	@Override
	public void onModuleLoad() {

		getSessionInfo();

		initGUI();

	}

	private void getNotiboxNotifications(String string) {

		tabs[3].clear();

		messageBoxService.downloadNotifications(session.get(1), new AsyncCallback<List<Notification>>() {

			@Override
			public void onFailure(Throwable caught) {
				Window.alert(caught.toString());
			}

			@Override
			public void onSuccess(List<Notification> result) {

				final VerticalPanel panel = new VerticalPanel();
				final ScrollPanel spanel = new ScrollPanel(panel);

				for (int i = 0; i < result.size(); ++i) {
					final int type;
					Notification noti = result.get(i);
					final Friendship friendshipInvitation;
					final ProjectAssoc participationInvitation;
					if (noti instanceof Friendship) {
						friendshipInvitation = (Friendship) noti;
						participationInvitation = null;

						type = 1;
					} else if (noti instanceof ProjectAssoc) {
						participationInvitation = (ProjectAssoc) noti;
						friendshipInvitation = null;
						type = 2;
					} else {
						type = 3;
						friendshipInvitation = null;
						participationInvitation = null;
					}

					final HorizontalPanel each = new HorizontalPanel();
					notis.add(each);

					Label text = new Label((type == 1 ? friendshipInvitation.getInviter() : participationInvitation.getProjectname())
							+ (type == 1 ? (" has added you at " + friendshipInvitation.getDateOfInvitation()) : ""));
					Button confirm = new Button("Confirm");

					confirm.addClickHandler(new ClickHandler() {

						@Override
						public void onClick(ClickEvent event) {
							if (type == 1) {
								messageBoxService.replyInvitation(friendshipInvitation, true, new AsyncCallback<Boolean>() {

									@Override
									public void onFailure(Throwable caught) {
										Window.alert(caught.toString());
									}

									@Override
									public void onSuccess(Boolean result) {
										if (!result) {
											Window.alert("Confirmation failed");
										} else {
											panel.remove(each);

										}

									}
								});

							} else {
								messageBoxService.respondParticipationInvitation(participationInvitation, true, new AsyncCallback<Boolean>() {

									@Override
									public void onFailure(Throwable caught) {
										Window.alert(caught.toString());
									}

									@Override
									public void onSuccess(Boolean result) {
										if (!result) {
											Window.alert("Confirmation failed");
										} else {
											panel.remove(each);

										}

									}
								});
							}
						}

					});

					Button reject = new Button("Reject");

					reject.addClickHandler(new ClickHandler() {

						@Override
						public void onClick(ClickEvent event) {
							if (type == 1) {
								messageBoxService.replyInvitation(friendshipInvitation, false, new AsyncCallback<Boolean>() {

									@Override
									public void onFailure(Throwable caught) {
										Window.alert("Confirmation failed!");

									}

									@Override
									public void onSuccess(Boolean result) {
										panel.remove(each);

									}
								});
							} else {
								messageBoxService.respondParticipationInvitation(participationInvitation, false, new AsyncCallback<Boolean>() {

									@Override
									public void onFailure(Throwable caught) {
										Window.alert(caught.toString());
									}

									@Override
									public void onSuccess(Boolean result) {
										if (!result) {
											Window.alert("Confirmation failed");
										} else {
											panel.remove(each);

										}

									}
								});
							}

						}
					});

					each.add(text);
					each.add(confirm);
					each.add(reject);

					panel.add(each);

				}

				spanel.setHeight("600px");

				tabs[3].add(spanel);

			}
		});

	}

	private void getSessionInfo() {
		messageBoxService.getSessionInfo(new AsyncCallback<List<String>>() {

			@Override
			public void onFailure(Throwable caught) {
			}

			@Override
			public void onSuccess(List<String> result) {
				session = result;
				getInboxMessages(session.get(1));
			}

		});
	}

	private void getInboxMessages(String username) {

		messageBoxService.downloadMessages(username, false, new AsyncCallback<List<Message>>() {
			public void onFailure(Throwable caught) {
				// Show the RPC error message to the user

				Window.alert("A Problem occured during downloading messages!");

			}

			public void onSuccess(final List<Message> results) {

				inboxMessages = results;
				AsyncDataProvider<Message> provider = new AsyncDataProvider<Message>() {
					@Override
					protected void onRangeChanged(HasData<Message> display) {
						int start = display.getVisibleRange().getStart();
						int end = start + display.getVisibleRange().getLength();
						end = end >= results.size() ? results.size() : end;
						List<Message> sub = results.subList(start, end);
						updateRowData(start, sub);
					}
				};

				provider.addDataDisplay(inbox);
				provider.updateRowCount(results.size(), true);

			}

		});
	}

	private void getSentboxMessages(String username) {

		messageBoxService.downloadMessages(username, true, new AsyncCallback<List<Message>>() {
			public void onFailure(Throwable caught) {
				// Show the RPC error message to the user

				Window.alert("A Problem occured during downloading messages!");
			}

			public void onSuccess(final List<Message> results) {

				sentboxMessages = results;
				AsyncDataProvider<Message> provider = new AsyncDataProvider<Message>() {
					@Override
					protected void onRangeChanged(HasData<Message> display) {
						int start = display.getVisibleRange().getStart();
						int end = start + display.getVisibleRange().getLength();
						end = end >= results.size() ? results.size() : end;
						List<Message> sub = results.subList(start, end);
						updateRowData(start, sub);
					}
				};
				provider.addDataDisplay(sentbox);
				provider.updateRowCount(results.size(), true);

			}

		});
	}

	private void sendMessage(Message msg) {

		messageBoxService.uploadMessage(msg, new AsyncCallback<Boolean>() {

			@Override
			public void onFailure(Throwable caught) {
			}

			@Override
			public void onSuccess(Boolean result) {
				if (result) {
					Window.alert("Message Sent");
					to.setText("");
					subject.setText("");
					content.setText("");
					tabPanel.selectTab(1);
				} else {
					Window.alert("Message Failed!");
				}

			}

		});

	}

	private final DecoratedTabPanel tabPanel = new DecoratedTabPanel();
	private AbsolutePanel[] tabs = null;
	private CellTable<Message> inbox = null;
	private CellTable<Message> sentbox = null;
	private TextArea messageContent = null;
	private TextArea messageContent2 = null;

	final Label tol = new Label("To");
	final TextBox to = new TextBox();
	final Label subjectl = new Label("Subject");
	final TextBox subject = new TextBox();
	final Label contentl = new Label("Content");
	final RichTextArea content = new RichTextArea();
	final Button send = new Button();

	LinkedList<HorizontalPanel> notis = new LinkedList<HorizontalPanel>();

	//
	List<Message> inboxMessages = null;
	List<Message> sentboxMessages = null;
	List<String> session = null;

}
